package pl.edu.mimuw.irs.rcp.controller.editor.generator;

import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.EventObject;
import java.util.List;

import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.gef.DefaultEditDomain;
import org.eclipse.gef.EditDomain;
import org.eclipse.gef.EditPartFactory;
import org.eclipse.gef.EditPartViewer;
import org.eclipse.gef.GraphicalViewer;
import org.eclipse.gef.commands.CommandStack;
import org.eclipse.gef.commands.CommandStackListener;
import org.eclipse.gef.editparts.ScalableFreeformRootEditPart;
import org.eclipse.gef.tools.SelectionTool;
import org.eclipse.gef.ui.parts.ScrollingGraphicalViewer;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IEditorSite;
import org.eclipse.ui.ISelectionListener;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.part.EditorPart;

import pl.edu.mimuw.irs.core.model.analysis.History;
import pl.edu.mimuw.irs.core.model.analysis.Report;
import pl.edu.mimuw.irs.core.model.analysis.workflow.AnalysisWorkflow;
import pl.edu.mimuw.irs.rcp.controller.editor.IWorkflowEditor;
import pl.edu.mimuw.irs.rcp.controller.editor.generator.part.GeneratorEditPartFactory;

public class GeneratorEditor extends EditorPart implements IWorkflowEditor {

	// *** Static attributes
	public static final String ID = "pl.edu.mimuw.irs.editor.generator";

	// *** Attributes
	private AnalysisWorkflow workflow;
	private Report report;
	private EditDomain editDomain;
	private boolean dirty;
	public AnalysisWorkflow getWorkflow() {
		return workflow;
	}
	public AnalysisWorkflow getModel() {
		return getWorkflow();
	}
	public Report getReport() {
		return report;
	}
	private CommandStackListener commandStackListener = new CommandStackListener() {
		public void commandStackChanged(EventObject event) {
			setDirty(getCommandStack().isDirty());
		}
	};
	private ISelectionListener selectionListener = new ISelectionListener() {
		public void selectionChanged(IWorkbenchPart part, ISelection selection) {
			//updateActions(editPartActionIDs);
		}
	};
	private PropertyChangeListener runsListener = new PropertyChangeListener() {
		@SuppressWarnings("unchecked")
		@Override
		public void propertyChange(PropertyChangeEvent evt) {
			if (!(evt.getNewValue() instanceof List<?>)) return;
			List<History> list = (List<History>) evt.getNewValue();
			setContentDescription("Applicable runs: " + list.size());
		}
	};
	private GraphicalViewer graphicalViewer;
	private EditPartFactory editPartFactory;
	// Getters and setters
	protected EditDomain getEditDomain() {
		if (editDomain == null) editDomain = new DefaultEditDomain(this);
		return editDomain;
	}
	public CommandStack getCommandStack() {
		return getEditDomain().getCommandStack();
	}
	protected CommandStackListener getCommandStackListener() {
		return commandStackListener;
	}
	@Override
	public boolean isDirty() {
		return dirty;
	}
	protected void setDirty(boolean dirty) {
		if (this.dirty != dirty) {
			this.dirty = dirty;
			firePropertyChange(IEditorPart.PROP_DIRTY);
		}
	}
	public GraphicalViewer getGraphicalViewer() {
		return graphicalViewer;
	}
	public EditPartFactory getEditPartFactory() {
		if (editPartFactory == null) editPartFactory = new GeneratorEditPartFactory();
		return editPartFactory;
	}
	protected ISelectionListener getSelectionListener() {
		return selectionListener;
	}
	public PropertyChangeListener getRunsListener() {
		return runsListener;
	}
	
	// *** Constructors
	
	public GeneratorEditor() {
		getEditDomain().setActiveTool(new SelectionTool());
	}

	// *** Methods
	
	public void createPartControl(Composite parent){
		graphicalViewer = createGraphicalViewer(parent);
	}
	
	@Override
	public void setFocus() {
	}
	
	@Override
	public void doSave(IProgressMonitor monitor) {
		// XXX save
		
		//getCommandStack().markSaveLocation();
	}
	
	@Override
	public void doSaveAs() {
		// XXX : save as

		//getCommandStack().markSaveLocation();
	}
	
	@Override
	public boolean isSaveAsAllowed() {
		return true;
	}
	
	public void init(IEditorSite site, IEditorInput input) throws PartInitException {
		// store site and input
		setSite(site);
		setInput(input);
		// add CommandStackListener
		getCommandStack().addCommandStackListener(getCommandStackListener());
		
		// add selection change listener
		getSite().getWorkbenchWindow().getSelectionService().addSelectionListener(
				getSelectionListener());
	}
	
	@Override
	public void dispose() {
		// remove CommandStackListener
		getCommandStack().removeCommandStackListener(getCommandStackListener());
		// remove selection listener
		getSite().getWorkbenchWindow().getSelectionService().removeSelectionListener(
				getSelectionListener());
		
		super.dispose();
	}
	
	protected GraphicalViewer createGraphicalViewer(Composite parent) {

		GraphicalViewer viewer = new ScrollingGraphicalViewer();
		viewer.createControl(parent);
		
		// configure the viewer
		viewer.getControl().setBackground(new Color(null, 255,255,255));

		viewer.setRootEditPart(new ScalableFreeformRootEditPart());
		// hook the viewer into the EditDomain
		getEditDomain().addViewer(viewer);
		
		// activate the viewer as selection provider for Eclipse
		getSite().setSelectionProvider(viewer);
		// initialize the viewer with input
		viewer.setEditPartFactory(getEditPartFactory());
		viewer.setContents(getModel());
		
		return viewer;
	}
	
	@Override
	protected void setInput(IEditorInput input) {
		super.setInput(input);
		
		GeneratorEditorInput editorInput = (GeneratorEditorInput)input;
		workflow = editorInput.getWorkflow();
		report = editorInput.getReport();
		
		//Resources resources = loadResources(getEditorInput());
		//workflow.setResources(resources);
		
	}

	@SuppressWarnings("unchecked")
	public Object getAdapter(Class adapter) {
		// we need to handle common GEF elements we created
		if (adapter == GraphicalViewer.class || adapter == EditPartViewer.class) {
			return getGraphicalViewer();
		} else if (adapter == CommandStack.class) {
			return getCommandStack();
		} else if (adapter == EditDomain.class) {
			return getEditDomain();
		} else {
			// the super implementation handles the rest
			return super.getAdapter(adapter);
		}
	}
}
